#include "stm32f10x.h"
#include "Delay.h"
#include "I2C_SOFT_GPIO.h"



static void set_sda(uint8_t bit){
    if(bit){
        GPIO_SetBits(GPIOB,sda);
    }else{
        GPIO_ResetBits(GPIOB,sda);
    }
    Delay_us(10);
}

static void set_scl(uint8_t bit){
    if(bit){
        GPIO_SetBits(GPIOB,scl);
        
    }else{
        GPIO_ResetBits(GPIOB,scl);
    }
    Delay_us(100);
}

static void start_condition(void){

    set_scl(1);
    set_sda(1);
    set_sda(0);
    
}


static void stop_condition(void){

    set_scl(1);
    set_sda(0);
    set_sda(1);
}

/**
    返回 1 代表从机已应答
*/
uint8_t read_slave_ack(void){
    
    set_scl(0);
	 // 释放 sda 
    set_sda(1); 
    set_scl(1);  

   // 开漏 模式下，可以通过GPIO直接读取输入寄存器的值
	// 等待从机相应
	 
	
	uint8_t result =  GPIO_ReadInputDataBit(GPIOB,sda) == Bit_RESET;

	 set_scl(0);   	
    
    return result;
    
}

static uint8_t write_byte(uint8_t data){

   
    uint8_t  bit;
    for(uint8_t mask = 0x80,i=7;mask!=0;mask>>=1,i--){
    
        set_scl(0);
        
        bit = data & mask;
        
        set_sda(bit>>i);
        
        set_scl(1);
        
        
    }
		
    return read_slave_ack();
}

void write(const uint8_t slave_address,const uint8_t * data,const uint8_t data_count){

    start_condition();
    
    uint8_t addr_byte = slave_address << 1 | 0;
    
    write_byte(addr_byte);
	
	
    for(uint8_t i =0;i<data_count;i++){
        
        write_byte(data[i]);
    }
    
    
    stop_condition();
}

void readCommandPrefix(const uint8_t slave_address,const uint8_t command){
    
    start_condition();
    
    uint8_t addr_byte = slave_address << 1 ;
    
    write_byte(addr_byte|0);
	
    write_byte(command);
    
    start_condition();
    
    write_byte(addr_byte|1);

}

uint8_t readSingleByte(){
    /*
        读取数据
    */
    uint8_t result=0;
    
    for(uint8_t i=0;i<8;i++){
    
        set_scl(0);
        set_scl(1);
        result|=GPIO_ReadInputDataBit(GPIOB,sda);
        result<<=1;
            
    }
    return result;

}

uint8_t read(const uint8_t slave_address,const uint8_t command){
    

    readCommandPrefix(slave_address,command);
  
    uint8_t result = readSingleByte();
    // 给从机 Nack
    set_scl(0);
    set_sda(1);
    set_scl(1);
    
    stop_condition();
    
    return result;
}

void readNByte(const uint8_t slave_address,const uint8_t command,uint8_t * dest_data,uint8_t nByte){

    readCommandPrefix(slave_address,command);
  
    uint8_t i=0;
    
    for(;i<nByte-1;i++){
    
        dest_data[i] = readSingleByte();
        
        // 给从机ack，代表让从机继续发送数据
        set_scl(0);
        set_sda(0);
        set_scl(1);
        // 释放 sda 线
        set_sda(1);
    }
    
    dest_data[i]=readSingleByte();
    
    // 给从机 Nack
    set_scl(0);
    set_sda(1);
    set_scl(1);
    
    stop_condition();
  
}



/**
@param scl_pin scl 的引脚号
@param sda_pin sda 的引脚号
@param slave_addr 此次I2C要通信的从机地址（6位）

*/
void init_gpio(uint16_t scl_pin,uint16_t sda_pin){

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    
    GPIO_Init(GPIOB,&(GPIO_InitTypeDef){
    
        .GPIO_Pin = scl_pin | sda_pin,
        .GPIO_Speed = GPIO_Speed_2MHz,
        // I2C 通信要求配置为开漏 输出
        .GPIO_Mode = GPIO_Mode_Out_OD
    });
    
    scl = scl_pin;
    sda= sda_pin;
    
    // 默认 scl 和 sda 都是高电平
    set_scl(1);
    set_sda(1);

    
}



